// 定义访问者模式的相关 trait 和结构体

// 定义 Visitor trait，声明访问具体元素的方法
trait Visitor {
    fn visit_concrete_element_a(&self, element: &ConcreteElementA);
    fn visit_concrete_element_b(&self, element: &ConcreteElementB);
}

// 定义 Element trait，声明接受访问者的方法
trait Element {
    fn accept(&self, visitor: &dyn Visitor);
}

// 具体元素 ConcreteElementA
struct ConcreteElementA;

// 实现 Element trait for ConcreteElementA
impl Element for ConcreteElementA {
    // 具体元素 A 接受访问者，并调用访问者的对应方法
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_concrete_element_a(self);
    }
}

// 具体元素 ConcreteElementB
struct ConcreteElementB;

// 实现 Element trait for ConcreteElementB
impl Element for ConcreteElementB {
    // 具体元素 B 接受访问者，并调用访问者的对应方法
    fn accept(&self, visitor: &dyn Visitor) {
        visitor.visit_concrete_element_b(self);
    }
}

// 具体访问者 ConcreteVisitor1
struct ConcreteVisitor1;

// 实现 Visitor trait for ConcreteVisitor1
impl Visitor for ConcreteVisitor1 {
    // 访问具体元素 A 的方法实现
    fn visit_concrete_element_a(&self, _element: &ConcreteElementA) {
        println!("ConcreteVisitor1: Visiting ConcreteElementA");
    }

    // 访问具体元素 B 的方法实现
    fn visit_concrete_element_b(&self, _element: &ConcreteElementB) {
        println!("ConcreteVisitor1: Visiting ConcreteElementB");
    }
}

// 具体访问者 ConcreteVisitor2
struct ConcreteVisitor2;

// 实现 Visitor trait for ConcreteVisitor2
impl Visitor for ConcreteVisitor2 {
    // 访问具体元素 A 的方法实现
    fn visit_concrete_element_a(&self, _element: &ConcreteElementA) {
        println!("ConcreteVisitor2: Visiting ConcreteElementA");
    }

    // 访问具体元素 B 的方法实现
    fn visit_concrete_element_b(&self, _element: &ConcreteElementB) {
        println!("ConcreteVisitor2: Visiting ConcreteElementB");
    }
}

// 主函数入口
pub fn main() {
    // 创建包含具体元素的集合
    let elements: Vec<Box<dyn Element>> =
        vec![Box::new(ConcreteElementA), Box::new(ConcreteElementB)];

    // 创建具体的访问者实例
    let visitor1 = ConcreteVisitor1;
    let visitor2 = ConcreteVisitor2;

    // 遍历元素集合，并对每个元素接受不同的访问者进行访问操作
    for element in &elements {
        element.accept(&visitor1);
        element.accept(&visitor2);
    }
}
